﻿using System;
using System.IO;
using EnvDTE;
using Microsoft.Practices.RecipeFramework;
using Microsoft.Practices.RecipeFramework.Library;
using Microsoft.Practices.RecipeFramework.Library.Actions;
using ProjectBase.Guidance.Helpers;

namespace ProjectBase.Guidance.Actions
{
    /// <summary>
    /// Add a new item from a string template into a given solution folder/project
    /// </summary>     
    public class AddItemToFolderAction : AddItemFromStringAction
    {
        private int _buildAction = 1;
        private bool _checkRecursive = true;
        private string _parentItem;
        private bool cont = true;
        private bool overwrite;

        /// <summary> 
        /// Overwrite an existing item
        /// </summary> 
        public bool Overwrite
        {
            get { return overwrite; }
            set { overwrite = value; }
        }

        /// <summary>
        /// The item that should be the parent of the new item
        /// </summary>
        [Input(Required = false)]
        public string ParentItem
        {
            get { return _parentItem; }
            set { _parentItem = value; }
        }

        /// <summary>
        /// When checking if the file already exists, check recursive or not
        /// </summary>
        [Input(Required = false)]
        public bool CheckRecursive
        {
            get { return _checkRecursive; }
            set { _checkRecursive = value; }
        }

        /// <summary>
        /// Set this to true if you want the added item to be copied to the output directory
        /// of a build
        /// </summary>
        [Input(Required = false)]
        public bool CopyToOutputDirectory { get; set; }

        /// <summary>
        // the BuildAction property needs to be one of the prjBuildAction enumeration
        // values:
        // - 0 : prjBuildActionNone
        // - 1 : prjBuildActionCompile
        // - 2 : prjBuildActionContent
        // - 3 : prjBuildActionEmbeddedResource
        // - 5 : prjBuildActionPage
        /// </summary>
        //[Input(Required = false)]
        public int BuildAction
        {
            get { return _buildAction; }
            set { _buildAction = value; }
        }

        [Input(Required = false)]
        public string Namespace { get; set; }

        /// <summary> 
        /// Continue after this action
        /// </summary> 
        [Output]
        public bool Continue
        {
            get { return cont; }
        }

        /// <summary>
        /// Current project default namspace (first part like Company.Product.Data)
        /// </summary>
        [Input(Required = false)]
        public string ProjectNamespace { get; set; }

        /// <summary>
        /// Special prefix which can be adde (et beginning)
        /// to FolderNamespace.
        /// </summary>
        [Input(Required = false)]
        public string MiddleNamespace { get; set; }

        /// <summary>
        /// The Namespace, which should be converted into folder structure 
        /// e.g. serivce.helper.dao = service\helper\dao
        /// </summary>
        [Input(Required = false)]
        public string FolderNamespace { get; set; }

        /// <summary>
        /// Possible suffix like 'Search', 'hbm' to nest file in special subfolder
        /// </summary>
        [Input(Required = false)]
        public string FolderSuffix { get; set; }

        [Input(Required = false)]
        public bool UseSimpleCodeList { get; set; }

        #region special settings for file skipping

        /// <summary>
        /// When XML as DAO is used, this will allow to skip this action 
        /// in case when the XML is value provided
        /// </summary>
        [Input(Required = false)]
        public string SkipFileForNotXmlDao { get; set; }

        protected bool DoSkipFileForNotXmlDao
        {
            get
            {
                if (!string.IsNullOrEmpty(SkipFileForNotXmlDao)
                    && !SkipFileForNotXmlDao.Equals("XML", StringComparison.OrdinalIgnoreCase))
                {
                    return true;
                }
                return false;
            }
        }

        /// <summary>
        /// When NHibernate as DAO is used, this will allow to skip this action 
        /// in case when the NHibernate is value provided
        /// </summary>
        [Input(Required = false)]
        public string SkipFileForNotNHDao { get; set; }

        protected bool DoSkipFileForNotNHDao
        {
            get
            {
                if (!string.IsNullOrEmpty(SkipFileForNotNHDao)
                    && !SkipFileForNotNHDao.Equals("NHibernate", StringComparison.OrdinalIgnoreCase))
                {
                    return true;
                }
                return false;
            }
        }

        #endregion special settings for file skipping

        /// <summary> 
        /// The method that creates a new item from the intput string. 
        /// </summary> 
        public override void Execute()
        {
            SwitchOffContinue();

            if (DoSkipFileForNotXmlDao)
            {
                return;
            }

            if (DoSkipFileForNotNHDao)
            {
                return;
            }

            var vs = GetService<DTE>(true);
            ProjectItems projectItems;
            if (string.IsNullOrEmpty(Namespace)
                || (!string.IsNullOrEmpty(ProjectNamespace) && !string.IsNullOrEmpty(FolderNamespace)))
            {
                Namespace = ProjectNamespace + "." + MiddleNamespace;
                if (FolderNamespace != "root")
                {
                    Namespace += "." + FolderNamespace;
                }
                if (!string.IsNullOrEmpty(FolderSuffix))
                {
                    Namespace += "." + FolderSuffix;
                }
                //Namespace = ProjectNamespace + "." + MiddleNamespace;
                //if (FolderNamespace != "root")
                //{
                //    Namespace += "." + FolderNamespace;
                //}
                //if (!string.IsNullOrEmpty(FolderSuffix))
                //{
                //    Namespace += "." + FolderSuffix;
                //}
            }
            ProjectItem currentFolder = SolutionHelper.FindOrCreateSelectedFolderInGivenProject(Project, Namespace);

            projectItems = (currentFolder != null ? currentFolder.ProjectItems : Project.ProjectItems);

            if (projectItems == null)
            {
                return;
            }

            bool generated = true;
            ProjectItem = DteHelper.FindItemByName(projectItems, TargetFileName, _checkRecursive);

            if (ProjectItem != null)
            {
                // the item already exists
                if (overwrite)
                {
                    OverwriteExistingFile();
                }
                else
                {
                    generated = false;
                }
            }
            else
            {
                if (_parentItem == null)
                {
                    AddNewFile(projectItems);
                }
                else
                {
                    AddNewFile(DteHelper.FindItemByName(projectItems, _parentItem, false).ProjectItems);
                }
            }

            if (generated)
            {
                object activeTarget = DteHelper.GetTarget(vs);
                // IMPORTANT: Restore previously selected target in the IDE.
                VisualStudioHelper.SelectItemInExplorer(vs, activeTarget);
            }
        }

        private void SwitchOffContinue()
        {
            ActionCoordinator.Continue = !UseSimpleCodeList;
        }

        private void AddNewFile(ProjectItems projectItems)
        {
            string tempFileName = Path.GetTempFileName();
            WriteContentToFile(tempFileName);
            ProjectItem = projectItems.AddFromTemplate(tempFileName, TargetFileName);
            SetCopyToOutputDirectoryPropertyIfNecessary(ProjectItem);
            SetBuildAction(ProjectItem);
            File.Delete(tempFileName);
        }

        private void OverwriteExistingFile()
        {
            SourceControlHelper.Checkout(ProjectItem);
            WriteContentToFile(Utils.SafeToString(ProjectItem.Properties.Item("LocalPath").Value));
            SetCopyToOutputDirectoryPropertyIfNecessary(ProjectItem);
            SetBuildAction(ProjectItem);
        }

        private void SetCopyToOutputDirectoryPropertyIfNecessary(ProjectItem projectItem)
        {
            if (CopyToOutputDirectory)
            {
                // the value needs to be one of Microsofts __COPYTOOUTPUTSTATE Enumeration:
                // 0 = Never
                // 1 = Always
                // 2 = PreserveNewest
                projectItem.Properties.Item("CopyToOutputDirectory").Value = "2";
            }
        }

        private void SetBuildAction(ProjectItem projectItem)
        {
            if (_buildAction >= 0 && _buildAction <= 3)
            {
                projectItem.Properties.Item("BuildAction").Value = _buildAction;
            }
        }

        private void WriteContentToFile(string fileName)
        {
            using (var sw = new StreamWriter(fileName, false))
            {
                sw.WriteLine(Content);
            }
        }
    }
}